﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
using System.Runtime.Serialization;
using Skyper.Shared;
using System.Xml;

namespace Skyper.Service {
	public sealed class ServiceHost {
		#region Const
		public const int BufferLength = 4096;
		private static SkypeHost skype;
		private static readonly List<ServiceAddress> availableAddressList = new List<ServiceAddress>();
		#endregion
		#region Nested
		private class ClientHost {
			#region Fields
			private readonly TcpClient client;
			private readonly Thread rx;
			private readonly NetworkStream stream;
			private readonly MemoryStream mem;
			#endregion
			#region Constructor
			public ClientHost(TcpClient tcp) {
				this.client = tcp;
				this.rx = CreateReceiver(Run);
				this.mem = new MemoryStream();
				this.stream = this.client.GetStream();
				this.rx.Start();
			}
			#endregion
			#region Private
			private void Run() {
				try {
					while (client.Connected) {
						Byte[] data = new Byte[BufferLength];

						int r = this.stream.Read(data, 0, data.Length);

						this.mem.Write(data, 0, r);
						if (r == data.Length) {
							//More data commin in?
							continue;
						}

						this.Respond();
						break;
					}
				} finally {
					this.stream.Dispose();
					this.client.Close();
					this.mem.Dispose();
				}
			}
			private void Respond() {
				Byte[] income = this.mem.ToArray();

				String text = Encoding.UTF8.GetString(income);

				if (String.IsNullOrEmpty(text)) {
					return;
				}
				String[] lines = text.Split(new String[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);

				foreach (var line in lines) {
					if (String.IsNullOrEmpty(line)) {
						continue;
					}

					if (!line.StartsWith("ACTION")) {
						continue;
					}

					this.Respond(line);
				}
			}
			private void Respond(String path) {
				if (String.IsNullOrEmpty(path)) {
					return;
				}
				String data = path.Replace("ACTION: ", "");
				switch (data) {
					default:
						return;
					case "LOGIN":
						RespondLogin(path);
						break;
					case "GETCONTACTS":
						RespondGetContacts(path);
						break;
				}
			}

			private void RespondLogin(String data) {
				Byte[] buff = Encoding.UTF8.GetBytes("OK");
				this.stream.Write(buff, 0, buff.Length);
				
			}
			private void RespondGetContacts(String data) {
				var contacts = skype.GetContacts();
				var qry = from c in contacts
						   where c.Available
						   select c;
				var list = qry.ToArray();
				using (var mem = new MemoryStream()) {
					ContactModel.Suspend(mem, list);

					this.stream.Write(mem.ToArray(), 0, (int)mem.Length);
				}
			}
			#endregion
		}
		#endregion
		#region Fields
		private readonly TcpListener server;
		private readonly Thread tx;

		private bool abort;
		#endregion
		#region Constructor
		public ServiceHost(IPEndPoint endPoint) {
			this.server = CreateServer(endPoint);
			this.tx = CreateTransmiter(Run);
		}
		#endregion
		#region Private
		private static TcpListener CreateServer(IPEndPoint endPoint) {
			TcpListener socks = new TcpListener(endPoint);

			return socks;
		}
		private static Thread CreateTransmiter(ThreadStart method) {
			Thread thread = new Thread(method);
			thread.IsBackground = true;
			thread.Name = "Service TX";
			return thread;
		}
		private static Thread CreateReceiver(ThreadStart method) {
			Thread thread = new Thread(method);
			thread.IsBackground = true;
			thread.Name = "Client RX";
			return thread;
		}
		private void Run() {
			while (!abort) {
				try {
					var client = this.server.AcceptTcpClient();
					Console.WriteLine("Got Client: {0}", client.Client.RemoteEndPoint);
					new ClientHost(client);
				} catch {

				}
			}
		}

		#endregion
		#region Public
		public void Start() {
			this.abort = false;
			this.server.Start(10);
			this.tx.Start();
			Skype = new SkypeHost();
		}
		public void Stop() {
			abort = true;
			this.server.Stop();
			this.tx.Join();
		}
		public static IEnumerable<ServiceAddress> GetAddress() {
			if (availableAddressList.Count == 0){
				var host = Dns.GetHostName();

				var adr = Dns.GetHostAddresses(host);

				foreach (var item in adr) {
					if (item.IsIPv6LinkLocal) {
						continue;
					}
					if (item.IsIPv6Multicast) {
						continue;
					}
					if (item.IsIPv6SiteLocal) {
						continue;
					}
					if (item.IsIPv6Teredo) {
						continue;
					}
					availableAddressList.Add(new ServiceAddress(item));
				}
			}
			return availableAddressList;
		}
		#endregion
		#region Property
		public static SkypeHost Skype {
			get {
				return skype;
			}
			set {
				if (skype == null) {
					skype = value;
				}
			}
		}
		#endregion
	}
}
